package org.example.sec08;

import com.google.common.util.concurrent.Uninterruptibles;
import com.seaway.models.sec08.*;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import org.example.sec08.respository.AccountRespository;
import org.example.sec08.validator.RequestValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * @author Administrator
 */
public class BankService extends BankServiceGrpc.BankServiceImplBase {
    private static final Logger LOG = LoggerFactory.getLogger(BankService.class);

    @Override
    public void getAccountBalance(BalanceCheckRequest request, StreamObserver<AccountBalance> responseObserver) {
        RequestValidator.validateAccount(request.getAccountNumber()).map(Status::asRuntimeException).ifPresentOrElse(
                //检查有没有值 有值的话
                responseObserver::onError,
                //没值
                () -> sendAccountBalance(request, responseObserver));

    }

    private void sendAccountBalance(BalanceCheckRequest request, StreamObserver<AccountBalance> responseObserver) {
        var accountNumber = request.getAccountNumber();
        var balance = AccountRespository.getBalance(accountNumber);
        var accountBalance = AccountBalance.newBuilder().setAccountNumber(accountNumber).setBalance(balance).build();
        responseObserver.onNext(accountBalance);
        responseObserver.onCompleted();
    }

    @Override
    public void withDraw(WithDrawRequest request, StreamObserver<Money> responseObserver) {
        //校验
        RequestValidator.validateAccount(request.getAccountNumber()).or(() -> RequestValidator.isAmountDivisibleBy10(request.getAmount())).or(() -> RequestValidator.hasSufficientBalance(request.getAmount(), AccountRespository.getBalance(request.getAccountNumber()))).map(Status::asRuntimeException).ifPresentOrElse(responseObserver::onError, () -> sendMoney(request, responseObserver));
    }

    private void sendMoney(WithDrawRequest request, StreamObserver<Money> responseObserver) {
        try {
            int accountNumber = request.getAccountNumber();
            int amount = request.getAmount();
            for (int i = 0; i < (amount / 10); i++) {
                if (i == 3) {
                    throw new RuntimeException("oops");
                }
                var money = Money.newBuilder().setAmount(10).build();
                responseObserver.onNext(money);
                AccountRespository.deductAccount(accountNumber, 10);
                Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
            }
            responseObserver.onCompleted();
        } catch (Exception e) {
            responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).getCause());
        }
    }

}
